#!/usr/bin/python
# -*- coding: UTF-8 -*-
'''
Created on 30 jun 2011

@author: Joakim Lindskog

Copyright (c) 2011 Joakim Lindskog

This file is part of MyGarden.

    MyGarden is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MyGarden is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MyGarden.  If not, see <http://www.gnu.org/licenses/>.
'''
from gardenbase import gardensprite
import math, util, events
from cocos.director import director
from pyglet import window
from util import config

# List of all plant types
list = []
# Array of localised plant names
plant_names = {}

class Plant(gardensprite.GardenSprite):
    '''
    Plant is a representation for the different plants in the game
    '''
    RIPE_BONUS = 1.5
    HOVER_HEIGHT = 5
    seed_image = None

    def __init__(self):
        '''
        Constructor
        '''
        super(Plant, self).__init__(self.seed_image)
        self.seed_progress = 0.0
        self.z = 0
        self.selected = False
        self.image_anchor = self.width/2, 0
        self.seed_growth = 1.0/self.days_as_seed
        self.growth_speed = (1.0-self.start_scale)/self.days_until_ripe
        self.has_dispatched_ripe_event=False
        self.has_dispatched_growing_event=False
        
    def grow(self, bed, game, dt):
        '''
        Grows the plant a bit
        
        @param bed: the bed this plant is in
        @type bed: Bed
        
        @param game: the Game instance
        @type game: Game
        
        @param dt: time elapsed since the last update, in seconds
        @type dt: float
        '''
        # Check if it's too cold
        if bed.temperature < self.min_temperature:
            # Don't grow
            return
        # Check if ripe
        if self.ripe:
            if not self.has_dispatched_ripe_event:
                # Dispatch event
                self.has_dispatched_ripe_event=True
                world = self.get_world_point(self.x, self.y)
                events.EventBus().dispatch_event(events.RipePlantEvent(self, world[0], world[1]))
            return
        elif ((self.seed_progress < 1.0 and bed.water > self.water_need*0.01*dt)
              or (self.seed_progress >= 1.0 and bed.water > self.water_need*self.scale*dt)):
            # Check if in seed period
            if self.seed_progress < 1.0:
                self.seed_progress += self.seed_growth*dt\
                    * (1/(self.min_temperature*1.2-bed.temperature) if bed.temperature <= self.min_temperature*1.2 else 1.0)
                bed.water -= self.water_need*0.01
                if self.seed_progress >= 1.0:
                    self.image = self.grow_image
                    self.image_anchor = self.get_image_anchor()
                    self.scale = self.start_scale
                    if not self.has_dispatched_growing_event:
                        # Dispatch event
                        self.has_dispatched_growing_event=True
                        world = self.get_world_point(self.x, self.y)
                        events.EventBus().dispatch_event(events.PlantGrowingEvent(self, world[0], world[1]))
            elif bed.nutrients > self.nutrient_need*self.scale*dt:
                # Grow plant
                # Find if there are other plants too close
                competition = 1.0
                for veg in bed.plants:
                    if veg == self: continue
                    # Ignore seeds
                    if veg.seed_progress < 1.0: continue
                    dist = math.hypot(self.x-veg.x, (self.y-(Plant.HOVER_HEIGHT if self.selected else 0)-(veg.y-(Plant.HOVER_HEIGHT if veg.selected else 0)))*1.2)
                    if dist < self.optimal_distance:
                        # Account for scale - a lower competition value means more competition
                        competition *= (dist/(self.optimal_distance**0.8))/(veg.scale*2)
                # If scale is less than the competition value, grow
                if self.scale < competition:
                    # Grow less if it's almost too cold
                    self.scale += self.growth_speed\
                        * ((1/float(self.min_temperature*1.2-bed.temperature)) if (self.min_temperature*1.2 - bed.temperature) > 1.0 else 1.0)\
                        * competition*dt
                    # Need more water if it's almost too warm
                    bed.water -= self.water_need\
                        * (bed.temperature-self.max_temperature*.8 if bed.temperature > self.max_temperature*.8 else 1.0)\
                        * competition*self.scale*dt
                    bed.nutrients -= self.nutrient_need*competition*self.scale*dt
        
    def isRipe(self):
        '''
        @return: whether this plant is ripe
        @rtype: boolean
        '''
        return self.seed_progress >= 1.0 and self.scale >= 1.0
    
    ripe = property(isRipe)
    
    def getScore(self):
        '''
        @return: the final score for this plant
        @rtype: float
        '''
        return self.base_score*(self.scale)*(Plant.RIPE_BONUS if self.ripe else 1) if self.seed_progress >= 1.0 else 0
    
    score = property(getScore)
    
    def harvest(self):
        '''
        Harvests this plant
        '''
        if self.seed_progress >= 1.0:
            self.image = self.harvest_image
    
    # -------------------------
    # Static and class methods
    # -------------------------
    
    def get_cursor():
        '''
        @return: the cursor used with this plant type
        @rtype: MouseCursor
        '''
        return director.interpreter_locals["director"].window.get_system_mouse_cursor(window.BaseWindow.CURSOR_DEFAULT)
    get_cursor = staticmethod(get_cursor)
    
    def get_mouse_info_image(cls):
        '''
        @return: the mouse info image used with this plant type
        @rtype: Gardensprite
        '''
        img = gardensprite.GardenSprite(util.load_image("dist_circle.png"))
        img.opacity = 100
        seed = gardensprite.GardenSprite(cls.get_seed_image())
        img.scale = (cls.optimal_distance*2.0)/float(img.width)
        seed.image_anchor_y = 0
        seed.scale = 1/img.scale
        img.add(seed)
        return img
    get_mouse_info_image = classmethod(get_mouse_info_image)
    
    def get_seed_image(cls):
        '''
        @return: the image representing the seed for this plant type
        @rtype: Gardensprite
        '''
        if cls.seed_image == None:
            cls.init()
        return cls.seed_image
    get_seed_image = classmethod(get_seed_image)
        
    def get_image_anchor(cls):
        '''
        @return: the image anchor position for this plant type
        @rtype: tuple
        '''
        return cls.soil_anchor_x, cls.soil_anchor_y
    get_image_anchor = classmethod(get_image_anchor)
        
    def init(cls, loader):
        '''
        Initiate this plant
        '''
        cls.seed_image = util.load_image(cls.seed_image_name, loader=loader)
        cls.grow_image = util.load_image(cls.grow_image_name, loader=loader)
        cls.harvest_image = util.load_image(cls.harvest_image_name, loader=loader)
        cls.icon_image = util.load_image(cls.icon, util.get_default_icon(), loader=loader)
        cls.optimal_distance = cls.plant_distance*config.PX_PER_CM
    init = classmethod(init)